home *** CD-ROM | disk | FTP | other *** search
- Subject: v06i042: Page reverser for ditroff (ditrev)
- Newsgroups: mod.sources
- Approved: rs@mirror.UUCP
-
- Submitted by: cca!caip!uw-beaver!uw-wally!schwartz (Michael F. Schwartz)
- Mod.sources: Volume 6, Issue 42
- Archive-name: ditrev
-
- Documents generated by ditroff(1) come out with page 1 on the bottom and the
- last page on top when you print them. I got tired of having to manually
- reverse the pages, so I hacked up a filter that reverses the pages for you.
- It's simple to use, and runs pretty fast:
-
- ditrev [file]
-
- outputs to stdout an image like the input, except all the pages are reversed.
- So, to use this, use something like the following command:
-
- troff inputfile -t | ditrev | lpr -n
-
- (where the /usr/local/ditroff is before the /bin/troff version in your search
- path).
-
- Note: There is another program called psrev that reverses PostScript file pages
- (my filter reverses ditroff pages; ditroff output is translated to PostScript
- before being printed on laserwriters). More about the differences between
- these programs is described in the man page.
-
- - Mike Schwartz
- University of Washington Computer Science Department
- ihnp4!uw-beaver!schwartz (USENET)
- schwartz@wally.arpa (ARPANET)
- schwartz%wally.arpa@csnet-relay.arpa (CSNET)
-
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create:
- # ditrev.1
- # ditrev.c
- # makefile
- # This archive created: Fri Jun 27 15:47:59 1986
- export PATH; PATH=/bin:/usr/bin:$PATH
- echo shar: "extracting 'ditrev.1'" '(2762 characters)'
- if test -f 'ditrev.1'
- then
- echo shar: "will not over-write existing file 'ditrev.1'"
- else
- sed 's/^ X//' << \SHAR_EOF > 'ditrev.1'
- X.TH DITREV 1 local
- X.SH NAME
- Xditrev \- reverse ditroff(1) pages
- X.SH SYNOPSIS
- X.B ditrev
- X[file]
- X.SH DESCRIPTION
- X.I Ditrev
- Xreverses the pages in a ditroff
- Xfile (or stdin, if no file is
- Xspecified) and outputs to stdout. This is useful when sending typeset
- Xditroff output to a laser printer:
- Xditroff outputs the pages in an order that, without this filter, forces
- Xyou to manually reverse them all.
- X.PP
- XTo use this filter, you would use something like the following command:
- X.RS
- Xtroff file -t -Pps | ditrev | lpr -n -Pps
- X.RE
- X(where /usr/local/ditroff is ahead of /usr/bin in your search path).
- X.SH COMPARISON WITH PSREV
- XThere is another program called psrev
- Xthat reverses the pages of PostScript
- Xfiles. Since many laser printers (e.g., the MacIntosh LaserWriter) use
- XPostScript, one could do
- X.RS
- Xtroff file -t -Pps | dps | psrev | lpr -Pps
- X.RE
- X(dps translates between ditroff format and PostScript). Although I didn't know
- Xof the existence of psrev when I wrote
- X.I ditrev,
- Xit turns out that there are several advantages of
- X.I ditrev
- Xover psrev:
- X.IP 1.
- X.I Ditrev
- Xis more general - it works no matter what image format the printer accepts.
- XThus,
- X.I ditrev
- Xcan be used for any printer, and the user doesn't have to know what format
- Xthe printer expects.
- X.IP
- XOn the other hand, psrev works no matter what
- Xtext formatter generated the file, as long as the printer accepts
- XPostScript. But, since most text processors (Scribe and tex(1L) in
- Xparticular) output the pages in the correct order, this probably
- Xisn't too useful.
- X.IP 2.
- X.I Ditrev
- Xruns faster than psrev.
- X.IP 3.
- XNeither dps nor psrev seem to have man pages.
- X.IP 4.
- XDps is often only available on the machine
- Xwhich drives the printer, so you would actually have to do
- X.RS
- X.RS
- Xtroff file -t -Pps | rsh 'dps | psrev | lpr -Pps'
- X.RE
- XThis can become more complicated and installation dependent
- Xif these other filters aren't
- Xin your search path on the remote machine.
- X.RE
- X.SH AUTHOR
- XMike Schwartz, University of Washington Computer Science Department.
- X.ce 3
- Xihnp4!uw-beaver!schwartz (USENET)
- Xschwartz@wally.arpa (ARPANET)
- Xschwartz%wally.arpa@csnet-relay.arpa (CSNET)
- X.SH BUGS
- X.IP 1.
- XThe transformation performed is very simple; I discovered it by looking at the
- Xoutput of ditroff and the source of dsun(1). Thus, although this filter
- Xseems to work, I may have made some oversimplifications.
- X.IP 2.
- XInput is read into dynamically allocated buffers, and hence, for a large input
- Xfile, alot of memory is used (but no more than necessary, if compiled with
- X-DREALLOC). This could have been avoided by disallowing input from stdin and
- Xusing fseek(3) to move through the file. I didn't do this because I wanted to
- Xallow input to come from stdin.
- X.SH SEE ALSO
- Xtroff(1), ditroff(1), dsun(1), lpr(1), tex(1L), printcap(5).
- SHAR_EOF
- if test 2762 -ne "`wc -c < 'ditrev.1'`"
- then
- echo shar: "error transmitting 'ditrev.1'" '(should have been 2762 characters)'
- fi
- fi
- echo shar: "extracting 'ditrev.c'" '(5198 characters)'
- if test -f 'ditrev.c'
- then
- echo shar: "will not over-write existing file 'ditrev.c'"
- else
- sed 's/^ X//' << \SHAR_EOF > 'ditrev.c'
- X/* Program to reverse pages from input and print on stdout, for ditroff(1)
- X * input. This is useful when sending typeset ditroff output to a laser
- X * printer: ditroff outputs the pages in an order that, without this filter,
- X * forces you to manually reverse them all.
- X *
- X * The transformation is simple: Below is some sample input. The X's below
- X * represent any character other than "p"; "p" delimits pages, and "x trailer"
- X * delimits the end of the last page. Also, all lines start in column 1.
- X * Xstartingstuff
- X * p1
- X * Xpage1stuff
- X * p2
- X * Xpage2stuff
- X * x trailer
- X * Xfinalstuff
- X *
- X * This input, when run through this filter, will produce the following output:
- X * Xstartingstuff
- X * p2
- X * Xpage2stuff
- X * p1
- X * Xpage1stuff
- X * x trailer
- X * Xfinalstuff
- X *
- X * By Mike Schwartz, 6-24-86.
- X * ihnp4!uw-beaver!schwartz (USENET)
- X * schwartz@wally.arpa (ARPANET)
- X * schwartz%wally.arpa@csnet-relay.arpa (CSNET)
- X */
- X
- X
- X#include <stdio.h>
- X
- X#define PAGEBUFSIZE 30000 /* Number of bytes initially allocated for each
- X postscript page. I empirically determined that
- X this is plenty more than ever seems to be
- X needed (max was about 18k). If compiled with
- X -DREALLOC, there is no waste involved, since
- X the buffers are realloc'd after their size is
- X determined. There seems to be similar time and
- X CPU usage characteristics with or without
- X -DREALLOC, but the space used is considerably
- X less with -DREALLOC: a 320k input file caused
- X the dynamic size to grow to about 500k with
- X -DREALLOC, and to about 1200k without it. */
- X
- X#define MAXPAGES 500 /* Max number of pages in the document */
- X
- X#define PageDelim(Char) (Char == 'p')
- X#define EndOfAllPagesDelimString "x trailer"
- X#define EndOfAllPages(Line) (strncmp(Line, EndOfAllPagesDelimString, 9) == 0)
- X
- Xint PageIndex = 0;
- X
- Xmain(argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X FILE *InputFile = stdin;
- X char *InputBufPtr;
- X int CharIndex = 0;
- X char *PageBuf[MAXPAGES];
- X char *fgets(), *malloc(), *realloc();
- X
- X if (argc > 2) {
- X fputs("Usage: ditrev [file]\n", stderr);
- X exit(1);
- X }
- X
- X if (argc == 2) {
- X InputFile = fopen(argv[1], "r");
- X if (InputFile == NULL) {
- X perror("ditrev: fopen");
- X exit(1);
- X }
- X }
- X
- X PageBuf[PageIndex] = malloc(PAGEBUFSIZE);
- X if (PageBuf[PageIndex] == NULL)
- X Abort("malloc returned no storage");
- X
- X /* Copy preliminary stuff (before first page) from input to output */
- X do {
- X InputBufPtr = fgets(&PageBuf[PageIndex][CharIndex],
- X PAGEBUFSIZE, InputFile);
- X if (InputBufPtr == NULL) /* EOF */
- X Abort("Invalid input format");
- X if (PageDelim(*InputBufPtr))
- X break;
- X fputs(InputBufPtr, stdout);
- X } while(1);
- X
- X
- X /* Now read and store away all pages until hit EndOfAllPages */
- X do {
- X InputBufPtr = fgets(&PageBuf[PageIndex][CharIndex],
- X PAGEBUFSIZE, InputFile);
- X if (InputBufPtr == NULL) /* EOF */
- X Abort("Invalid input format");
- X if (EndOfAllPages(InputBufPtr)) {
- X /* Put a page delimeter into the end of this page so
- X we can find the end when we are printing everything
- X out */
- X *InputBufPtr = 'p';
- X break;
- X }
- X CharIndex += strlen(InputBufPtr) + 1;
- X /* +1 so we don't write over the null terminator */
- X if (CharIndex >= PAGEBUFSIZE) {
- X Abort("Page size being malloc'd is too small (recompile with larger PAGEBUFSIZE)");
- X }
- X if (PageDelim(*InputBufPtr)) {
- X#ifdef REALLOC
- X /* Now that we know how big this page is, realloc the
- X old page buffer so we don't waste unused space */
- X PageBuf[PageIndex] = realloc(PageBuf[PageIndex],
- X CharIndex);
- X if (PageBuf[PageIndex] == NULL)
- X Abort("realloc returned no storage");
- X#endif REALLOC
- X /* (Leave the page delimeter in place so we can find
- X the end of the old page when we are printing
- X everything out). Advance PageIndex, reset
- X CharIndex, and malloc more storage, so we can start
- X reading in the next page */
- X PageIndex++;
- X PageBuf[PageIndex] = malloc(PAGEBUFSIZE);
- X if (PageBuf[PageIndex] == NULL)
- X Abort("malloc returned no storage");
- X CharIndex = 0;
- X }
- X } while(1);
- X
- X
- X /* Now print out the buffered up pages in reverse order */
- X
- X for (PageIndex = PageIndex; PageIndex >= 0; PageIndex--) {
- X CharIndex = 0;
- X /* Output the page delimeter record expected by the drivers */
- X printf("p%d\n", PageIndex + 1);
- X do {
- X if (PageDelim(PageBuf[PageIndex][CharIndex]))
- X break;
- X fputs(&PageBuf[PageIndex][CharIndex], stdout);
- X CharIndex += strlen(&PageBuf[PageIndex][CharIndex]) + 1;
- X /* +1 to skip the null terminator */
- X } while(1);
- X }
- X
- X /* Now print out the final lines, starting with the end-pages
- X delimeter line */
- X puts(EndOfAllPagesDelimString);
- X PageIndex = 0;
- X CharIndex = 0;
- X#ifdef REALLOC
- X /* Current PageBuf may have been chopped off too short for final
- X stuff */
- X PageBuf[PageIndex] = realloc(PageBuf[PageIndex], PAGEBUFSIZE);
- X if (PageBuf[PageIndex] == NULL)
- X Abort("realloc returned no storage");
- X#endif REALLOC
- X do {
- X InputBufPtr = fgets(&PageBuf[PageIndex][CharIndex],
- X PAGEBUFSIZE, InputFile);
- X if (InputBufPtr == NULL) /* EOF */
- X exit(0);
- X fputs(InputBufPtr, stdout);
- X } while(1);
- X}
- X
- XAbort(Message)
- Xchar *Message;
- X{
- X fprintf(stderr, "ditrev: %s at page %d\n", Message, PageIndex);
- X exit(1);
- X}
- SHAR_EOF
- if test 5198 -ne "`wc -c < 'ditrev.c'`"
- then
- echo shar: "error transmitting 'ditrev.c'" '(should have been 5198 characters)'
- fi
- fi
- echo shar: "extracting 'makefile'" '(146 characters)'
- if test -f 'makefile'
- then
- echo shar: "will not over-write existing file 'makefile'"
- else
- sed 's/^ X//' << \SHAR_EOF > 'makefile'
- X# use -DREALLOC if you want this program to use realloc(1)
- XCFLAGS = -O -DREALLOC
- X
- Xditrev: ditrev.c
- X cc ${CFLAGS} -o ditrev ditrev.c
- X strip ditrev
- SHAR_EOF
- if test 146 -ne "`wc -c < 'makefile'`"
- then
- echo shar: "error transmitting 'makefile'" '(should have been 146 characters)'
- fi
- fi
- exit 0
- # End of shell archive
-